#pragma once
#pragma warning( disable: 4251 ) 

//WGLENGINE_DLL
#ifdef WGLENGINE_DLL
#define WGLENGINE_EXPORT __declspec(dllexport)
#else
#define WGLENGINE_EXPORT __declspec(dllimport)
#endif

#include <string>
#include "glm\glm.hpp"

enum UniformType {Float, Vec2, Vec3, UniformBlock, Null};

class WGLENGINE_EXPORT ShaderUniform
{
public:
	ShaderUniform(std::string name)
	{
		this->name = name;
		type = Null;
	}

	~ShaderUniform()
	{

	}

	std::string GetName() 
	{
		return name;
	}

	virtual void Upload()
	{

	}

protected:
	std::string name;
	UniformType type;
	int programID;
};

class WGLENGINE_EXPORT FloatShaderUniform : public ShaderUniform
{
public:
	FloatShaderUniform(std::string name, float param)
		: ShaderUniform(name)
	{
		this->param = param;
		type = Float;
	}

	float param;
};


class WGLENGINE_EXPORT Vec2ShaderUniform : public ShaderUniform
{
public:
	Vec2ShaderUniform(std::string name, glm::vec2 param)
		: ShaderUniform(name)
	{
		this->param = param;
		type = Vec2;
	}

	glm::vec2 param;
};

class WGLENGINE_EXPORT Vec3ShaderUniform : public ShaderUniform
{
public:
	Vec3ShaderUniform(std::string name, glm::vec3 param)
		: ShaderUniform(name)
	{
		this->param = param;
		type = Vec3;
	}

	glm::vec3 param;
};

class WGLENGINE_EXPORT UniformBlockUniform : public ShaderUniform
{
protected:
	void* param;
	int size;
	int bindingPt;

	GLuint ubo;
public:
	UniformBlockUniform(std::string name, void*& uniformBlock, int size, int programID, int bindingPt)
		: ShaderUniform(name)
	{
		this->programID = programID;

		this->param = uniformBlock;
		type = UniformBlock;

		this->size = size;
		this->bindingPt = bindingPt;
		
		GLuint skyBoxParamsLocation = glGetUniformBlockIndex(programID, name.c_str());
		glUniformBlockBinding(programID, skyBoxParamsLocation, bindingPt);

		glGenBuffers(1, &ubo);
		glBindBuffer(GL_UNIFORM_BUFFER, ubo);
		glBufferData(GL_UNIFORM_BUFFER, size, uniformBlock, GL_DYNAMIC_DRAW);
		glBindBuffer(GL_UNIFORM_BUFFER, 0);

		glBindBufferBase(GL_UNIFORM_BUFFER, bindingPt, ubo);
		
	}

	virtual void Upload() override
	{
		glBindBuffer(GL_UNIFORM_BUFFER, ubo);
		glBufferData(GL_UNIFORM_BUFFER, size, param, GL_DYNAMIC_DRAW);
		glBindBuffer(GL_UNIFORM_BUFFER, 0);

		/*glBindBuffer(GL_UNIFORM_BUFFER, ubo);
		GLvoid* p = glMapBuffer(GL_UNIFORM_BUFFER, GL_WRITE_ONLY);
		memcpy(p, &param, size);
		glUnmapBuffer(GL_UNIFORM_BUFFER);
		glBindBuffer(GL_UNIFORM_BUFFER, 0);*/
	}

	GLuint GetID()
	{
		return ubo;
	}
};